package danlib;

import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.lang.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import java.util.*;
import java.util.Arrays;
import java.util.Scanner;

public abstract class DProgram extends Canvas implements KeyListener, MouseListener, MouseMotionListener, MouseWheelListener
{
	public DWindow frame;
	public BufferStrategy strat;
	
	public Graphics2D g2 = null;
	public int frameRate = 30;
	public boolean dragZoom = false;
	public boolean fastForward = true;
	public boolean restartable = true;
	
	//KEYS
	public boolean ka = false;
	public boolean kb = false;
	public boolean kc = false;
	public boolean kd = false;
	public boolean ke = false;
	public boolean kf = false;
	public boolean kg = false;
	public boolean kh = false;
	public boolean ki = false;
	public boolean kj = false;
	public boolean kk = false;
	public boolean kl = false;
	public boolean km = false;
	public boolean kn = false;
	public boolean ko = false;
	public boolean kp = false;
	public boolean kq = false;
	public boolean kr = false;
	public boolean ks = false;
	public boolean kt = false;
	public boolean ku = false;
	public boolean kv = false;
	public boolean kw = false;
	public boolean kx = false;
	public boolean ky = false;
	public boolean kz = false;
	public boolean kup = false;
	public boolean kdown = false;
	public boolean kleft = false;
	public boolean kright = false;
	public boolean kenter = false;
	public boolean kspace = false;
	public boolean kctrl = false;
	public boolean kbackspace = false;
	
	public boolean keyPress = false;
	public String lastText = "";
	
	//MOUSE
	public boolean clicked = false;
	public boolean leftclicked = false;
	
	public int xMouse = 0;
	public int yMouse = 0;
	public int xLast = 0;
	public int yLast = 0;
	private int xDrag = 0;
	private int yDrag = 0;
	public int xDragged = 0;
	public int yDragged = 0;
	//Drag Beginning loc
	public int xStart = 0;
	public int yStart = 0;
	
	public int mouseWheel = 0;
	public int zoomLocX = 0;
	public int zoomLocY = 0;
	public double scale = 0;
	
	public AffineTransform tx = new AffineTransform();
	
	public Skin2D skin;
	
	boolean running = true;
	
	boolean restart = false;
	
	public JPanel panel = null;
	
	public void init()
	{
		frame = new DWindow();
		
		
		panel = (JPanel) frame.getContentPane();
		panel.setPreferredSize(new Dimension(800,600));
		panel.setLayout(null);

		setBounds(0,0,800,600);
		panel.add(this);
		setIgnoreRepaint(true);
		
		addKeyListener(this);
		addMouseListener(this);
		addMouseMotionListener(this);
		addMouseWheelListener(this);
		frame.pack();
		createBufferStrategy(2);
		strat = getBufferStrategy();
		start();
		run();
	}
	
	public void init(String title, int x, int y)
	{
		frame = new DWindow(title, x, y);
		
		JPanel panel = (JPanel) frame.getContentPane();
		panel.setPreferredSize(new Dimension(x,y));
		panel.setLayout(null);

		setBounds(0,0,800,600);
		panel.add(this);
		setIgnoreRepaint(true);
		addKeyListener(this);
		addMouseListener(this);
		addMouseMotionListener(this);
		addMouseWheelListener(this);
		frame.pack();
		createBufferStrategy(2);
		strat = getBufferStrategy();
		start();
		run();
	}
	
	public synchronized void run()
	{
		while(true)
		{
			if(running)
			{
				startWait(frameRate);
				if(restart)
				{
					start();
					restart = false;
				}
				update();
				paint();
				endWait();
			}
		}
	}
	
	
	public synchronized void paint()
	{
		Graphics2D g2 = (Graphics2D) strat.getDrawGraphics();
		g2.setColor( Color.WHITE );
		g2.fillRect( 0, 0, frame.getWidth(), frame.getHeight() );
		g2.setColor( Color.BLACK );
		if( skin == null )
		{
			skin = new Skin2D( g2 );
		}
		g2.setTransform(tx);
		draw(g2);
		g2.dispose();
		strat.show();
	}
	
	
	public abstract void draw( Graphics2D g2 );
	
	public abstract void update();
	
	public abstract void start();
	
	
	public static long time;
	public static double fps;
	
	public static void startWait(long a)
	{
		fps = a;
		time = System.currentTimeMillis();
	}
	
	public static void endWait()
	{
		while(System.currentTimeMillis()-time < 1000/fps)
		{
			try
			{
				Thread.sleep(2);
			}
			catch(Exception ex){}
		} 
	}
	
	
	public void mousePressed(MouseEvent e) 
	{
		if(e.getButton() == e.BUTTON1)
		{
		xStart = e.getX();
		yStart = e.getY();
		clicked = true;
		}
		if(e.getButton() == e.BUTTON3)
		{
			leftclicked = true;
		}
    }

    public void mouseReleased(MouseEvent e) 
	{
		if(e.getButton() == e.BUTTON1)
		{
		xDrag += e.getX() - xStart;
		yDrag += e.getY() - yStart;
		xDragged = 0;
		yDragged = 0;
		clicked = false;
		}
		if(e.getButton() == e.BUTTON3)
		{
			leftclicked = false;
		}
    }

    public void mouseEntered(MouseEvent e) 
	{

    }

    public void mouseExited(MouseEvent e) 
	{

    }

    public void mouseClicked(MouseEvent e) 
	{
		
    }
	
	public void mouseMoved(MouseEvent e)
	{
		xMouse = e.getX();
		yMouse = e.getY();
		
		xLast = e.getX();
		yLast = e.getY();
	}
	
	public void mouseDragged(MouseEvent e)
	{
		xMouse = e.getX();
		yMouse = e.getY();
		xDragged = e.getX() - xStart;
		yDragged = e.getY() - yStart;
		if( dragZoom )
		{
			tx.translate( (xMouse - xLast), (yMouse - yLast) );
		}
		xLast = e.getX();
		yLast = e.getY();
	}
	
	public void mouseWheelMoved( MouseWheelEvent e )
	{
		mouseWheel += e.getWheelRotation();
		zoomLocX = xMouse;
		zoomLocY = yMouse;
		if( dragZoom )
		{
			tx.translate( xMouse, yMouse );
			scale = 1 + e.getWheelRotation() * .1;
			tx.scale( scale, scale );
			tx.translate( -xMouse , -yMouse);
		}
	}
	
	public void keyTyped(KeyEvent e) 
	{

    }

    public void keyPressed(KeyEvent e) 
	{
		keyPress = true;
		int keyCode = e.getKeyCode();
		if(keyCode == KeyEvent.VK_P && fastForward)
			running = false;
		if(keyCode == KeyEvent.VK_F && fastForward)
			frameRate = 1000;
		switch( keyCode )
		{
			case KeyEvent.VK_A: ka = true; lastText = "a"; break;
			case KeyEvent.VK_B: kb = true; lastText = "b";break;
			case KeyEvent.VK_C: kc = true; lastText = "c";break;
			case KeyEvent.VK_D: kd = true; lastText = "d";break;
			case KeyEvent.VK_E: ke = true; lastText = "e";break;
			case KeyEvent.VK_F: kf = true; lastText = "f";break;
			case KeyEvent.VK_G: kg = true; lastText = "g";break;
			case KeyEvent.VK_H: kh = true; lastText = "h";break;
			case KeyEvent.VK_I: ki = true; lastText = "i";break;
			case KeyEvent.VK_J: kj = true; lastText = "j";break;
			case KeyEvent.VK_K: kk = true; lastText = "k";break;
			case KeyEvent.VK_L: kl = true; lastText = "l";break;
			case KeyEvent.VK_M: km = true; lastText = "m";break;
			case KeyEvent.VK_N: kn = true; lastText = "n";break;
			case KeyEvent.VK_O: ko = true; lastText = "o";break;
			case KeyEvent.VK_P: kp = true; lastText = "p";break;
			case KeyEvent.VK_Q: kq = true; lastText = "q";break;
			case KeyEvent.VK_R: kr = true; lastText = "r";break;
			case KeyEvent.VK_S: ks = true; lastText = "s";break;
			case KeyEvent.VK_T: kt = true; lastText = "t";break;
			case KeyEvent.VK_U: ku = true; lastText = "u";break;
			case KeyEvent.VK_V: kv = true; lastText = "v";break;
			case KeyEvent.VK_W: kw = true; lastText = "w";break;
			case KeyEvent.VK_X: kx = true; lastText = "x";break;
			case KeyEvent.VK_Y: ky = true; lastText = "y";break;
			case KeyEvent.VK_Z: kz = true; lastText = "z";break;
			case KeyEvent.VK_UP: kup = true; lastText = "up";break;
			case KeyEvent.VK_DOWN: kdown = true; lastText = "down";break;
			case KeyEvent.VK_LEFT: kleft = true; lastText = "left";break;
			case KeyEvent.VK_RIGHT: kright = true; lastText = "right";break;
			case KeyEvent.VK_ENTER: kenter = true; lastText = "enter";break;
			case KeyEvent.VK_SPACE: kspace = true; lastText = "space";break;
			case KeyEvent.VK_CONTROL: kctrl = true; lastText = "ctrl";break;
			case KeyEvent.VK_BACK_SPACE: kbackspace = true; lastText = "backspace";break;
		}
    }

    public void keyReleased(KeyEvent e) 
	{
		//keyPress = false;
		int keyCode = e.getKeyCode();
		if(keyCode == KeyEvent.VK_P && fastForward)
			running = true;
		if(keyCode == KeyEvent.VK_R && restartable)
			restart = true;
		if(keyCode == KeyEvent.VK_F && fastForward)
			frameRate = 60;
		switch( keyCode )
		{
			case KeyEvent.VK_A: ka = false; break;
			case KeyEvent.VK_B: kb = false; break;
			case KeyEvent.VK_C: kc = false; break;
			case KeyEvent.VK_D: kd = false; break;
			case KeyEvent.VK_E: ke = false; break;
			case KeyEvent.VK_F: kf = false; break;
			case KeyEvent.VK_G: kg = false; break;
			case KeyEvent.VK_H: kh = false; break;
			case KeyEvent.VK_I: ki = false; break;
			case KeyEvent.VK_J: kj = false; break;
			case KeyEvent.VK_K: kk = false; break;
			case KeyEvent.VK_L: kl = false; break;
			case KeyEvent.VK_M: km = false; break;
			case KeyEvent.VK_N: kn = false; break;
			case KeyEvent.VK_O: ko = false; break;
			case KeyEvent.VK_P: kp = false; break;
			case KeyEvent.VK_Q: kq = false; break;
			case KeyEvent.VK_R: kr = false; break;
			case KeyEvent.VK_S: ks = false; break;
			case KeyEvent.VK_T: kt = false; break;
			case KeyEvent.VK_U: ku = false; break;
			case KeyEvent.VK_V: kv = false; break;
			case KeyEvent.VK_W: kw = false; break;
			case KeyEvent.VK_X: kx = false; break;
			case KeyEvent.VK_Y: ky = false; break;
			case KeyEvent.VK_Z: kz = false; break;
			case KeyEvent.VK_UP: kup = false; break;
			case KeyEvent.VK_DOWN: kdown = false; break;
			case KeyEvent.VK_LEFT: kleft = false; break;
			case KeyEvent.VK_RIGHT: kright = false; break;
			case KeyEvent.VK_ENTER: kenter = false; break;
			case KeyEvent.VK_SPACE: kspace = false; break;
			case KeyEvent.VK_CONTROL: kctrl = false; break;
			case KeyEvent.VK_BACK_SPACE: kbackspace = false; break;
		}
    }
	
	

	

}